/**
 * FFmpegHandler.java 
 * Copyright © 2015-3015, 杭州泊享网络科技有限公司
 * 
 * @author Liu Tao
 * @create 2014年11月12日
 */
package com.pshare.util.video;

import java.io.File;
import java.util.HashSet;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

import com.pshare.constant.SeaxConstants;
import com.pshare.util.FileUtils;
import com.pshare.util.SysPropertyUtils;

/**
 * ffmpeg视频处理
 */
public class FFmpegHandler {

	protected static final Logger logger = Logger.getLogger(FFmpegHandler.class);

	private static final String FFMPEG_PATH = SysPropertyUtils.getProperty("ffmpeg.path");
	private static final String OUTPUT_TYPE = "mp4";
	private static final String PIC_OUTPUT_TYPE = "png";
	private static final String MIN_LENGTH = SysPropertyUtils.getProperty("video.length.min");
	private static final String MAX_LENGTH = SysPropertyUtils.getProperty("video.length.max");
	private static final String DEFAULT_MIN_LENGTH = "00:00:08";
	private static final String DEFAULT_MAX_LENGTH = "00:00:15";
	private static String MIN_TIME = null;
	private static String MAX_TIME = null;
	private static String SYS_CMD = "ffmpeg";
	private static final int SUCCESS = 0;

	private static Set<String> fileTypeSet = new HashSet<String>(); // ffmpeg能解析的格式

	static {
		fileTypeSet.add("avi");
		fileTypeSet.add("mpg");
		fileTypeSet.add("wmv");
		fileTypeSet.add("3gp");
		fileTypeSet.add("mov");
		fileTypeSet.add("mp4");
		fileTypeSet.add("asf");
		fileTypeSet.add("asx");
		fileTypeSet.add("flv");

		if (StringUtils.isBlank(MIN_LENGTH)) {
			logger.warn("video.length.min is blank, set as default value " + DEFAULT_MIN_LENGTH);
			MIN_TIME = DEFAULT_MIN_LENGTH;
		} else {
			int min = Integer.parseInt(MIN_LENGTH);
			if (min < 10) {
				MIN_TIME = "00:00:0" + MIN_LENGTH;
			} else if (min < 60) {
				MIN_TIME = "00:00:" + MIN_LENGTH;
			} else {
				logger.error("video.length.min " + MIN_LENGTH + " is wrong, set as default value " + DEFAULT_MIN_LENGTH);
				MIN_TIME = DEFAULT_MIN_LENGTH;
			}
		}

		if (StringUtils.isBlank(MIN_LENGTH)) {
			logger.warn("video.length.max is blank, set as default value " + DEFAULT_MIN_LENGTH);
			MAX_TIME = DEFAULT_MAX_LENGTH;
		} else {
			int max = Integer.parseInt(MAX_LENGTH);
			if (max < 10) {
				MAX_TIME = "00:00:0" + MAX_LENGTH;
			} else if (max < 60) {
				MAX_TIME = "00:00:" + MAX_LENGTH;
			} else {
				logger.error("video.length.max " + MAX_LENGTH + " is wrong, set as default value " + DEFAULT_MAX_LENGTH);
				MAX_TIME = DEFAULT_MAX_LENGTH;
			}
		}

		if (StringUtils.isBlank(FFMPEG_PATH)) {
			// 系统已部署好ffmpeg，不需要指定路径

		} else if (FFMPEG_PATH.endsWith(".bat") || FFMPEG_PATH.endsWith(".exe")) {
			// windows
			SYS_CMD = "cmd /c start " + FFMPEG_PATH;
		} else {
			// others
			SYS_CMD = FFMPEG_PATH;
		}
	}

	public static String process(String inputFile, boolean hasLong) {
		String generatedFile = null;
		if (checkContentType(inputFile)) {
			generatedFile = processFile(inputFile, hasLong);
		} else {
			throw new RuntimeException("不支持的视频格式");
		}
		return generatedFile;
	}

	public static void process(String inputFile, boolean hasLong, String cmdPath) {
		SYS_CMD = cmdPath;
		process(inputFile, hasLong);
	}

	/**
	 * 根据后缀名校验视频格式是否支持
	 * 
	 * @return boolean
	 */
	private static boolean checkContentType(String inputFile) {
		String type = inputFile.substring(inputFile.lastIndexOf(".") + 1, inputFile.length()).toLowerCase();
		return fileTypeSet.contains(type);
	}

	private static String processFile(String inputFile, boolean hasLong) {
		String fileName = null;
		File f = new File(inputFile);
		if (f.isFile()) {
			fileName = inputFile.substring(0, inputFile.lastIndexOf(SeaxConstants.POINT)) + "x." + OUTPUT_TYPE;
			try {
				String cmd = SYS_CMD + " -i " + inputFile
						+ " -y -r 25 -ab 32 -ac 2 -ar 24000 -s 320x180 -vcodec mpeg4 -strict experimental ";
				if (hasLong) {
					cmd += " -t " + MAX_TIME + " ";
				} else {
					cmd += " -t " + MIN_TIME + " ";
				}
				cmd += fileName;
				Process process = Runtime.getRuntime().exec(cmd);

				readProcessOutput(process);

				// 等待程序执行结束并输出状态
				int exitCode = process.waitFor();
				if (exitCode == SUCCESS) {
					logger.info("success");
				} else {
					logger.error("failed" + exitCode);
				}
			} catch (Exception e) {
				logger.error(e.getMessage(), e);
			}
		} else {
			logger.error("input file " + inputFile + " is not a file");
		}
		return fileName;
	}

	public static String screenShot(String filePath) {
		String picFile = null;
		File f = new File(filePath);
		if (f.isFile()) {
			picFile = filePath.substring(0, filePath.lastIndexOf(SeaxConstants.POINT) + 1) + PIC_OUTPUT_TYPE;
			try {
//				String cmd = SYS_CMD + " -ss 00:00:01 -i " + filePath + " -y -f image2 -s 320x180 ";
				String cmd = SYS_CMD + " -i " + filePath + " -y -f image2 -ss 00:00:01 -t 0.001 -s 320x180 ";
				cmd += picFile;
				Process process = Runtime.getRuntime().exec(cmd);

				readProcessOutput(process);

				// 等待程序执行结束并输出状态
				int exitCode = process.waitFor();
				if (exitCode == SUCCESS) {
					logger.info("success");
				} else {
					logger.error("failed" + exitCode);
				}
			} catch (Exception e) {
				logger.error(e.getMessage(), e);
			}
		} else {
			logger.error("input file " + picFile + " is not a file");
		}
		return picFile;
	}

	private static void readProcessOutput(final Process process) {
		// 将进程的正常输出在 System.out 中打印，进程的错误输出在 System.err 中打印
		FileUtils.readInputStream(process.getInputStream(), System.out);
		FileUtils.readInputStream(process.getErrorStream(), System.err);
	}

	public static void main(String[] args) {
		FFmpegHandler handler = new FFmpegHandler();
		handler.process("/Users/liutao/Documents/video/from/IMG_1478.MOV", false, "/opt/ffmpeg");
		// handler.process("/Users/liutao/Documents/video/from/1.mp4", false,
		// "/opt/ffmpeg");
	}

}
